<?php

namespace Ascf\Core;

use FastRoute\RouteCollector;
use function FastRoute\simpleDispatcher;
use Invoker\Invoker;
use FastRoute\Dispatcher;
use Throwable;

/**
 * 应用主类
 * 处理请求并调度到相应的控制器
 */
class App
{
    private static $instance = null;
    public static $config;
    private $factory;
    private $request;
    private $response;
    private $router;

    // 私有构造方法，防止直接实例化
    private function __construct()
    {
        self::$config =require APP_CONFIG;
        $this->factory = new AppFactory(self::$config);
        $this->init();

    }

    // 初始化方法，用于从容器获取依赖
    private function init()
    {
        $container = $this->factory->getContainer();
        $this->request = $container->get('request');
        $this->response = $container->get('response');
        $this->router = $container->get('router');

        // ...
    }

    // 提供一个获取实例的公共静态方法
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * 运行应用
     * 解析请求，分发路由，发送响应
     */
    public function run()
    {
        try {
            $uri = $this->request->getUri();
            $method = $this->request->getMethod();
            return $this->urlMatch($method, $uri);
        } catch (Throwable $e) {
            // 处理错误
           return $this->handleError($e);
        }
    }

    private function handleError(Throwable $e)
    {
        error_log($e->getMessage()); // 记录错误日志

        // 友好的错误信息对外展示
        $statusCode = $e instanceof NotFoundException ? 404 : 500;
        $message = $e instanceof NotFoundException ? 'Not Found' : 'Internal Server Error';

        $this->response->setContent($message);
        $this->response->setStatusCode($statusCode);
        $this->response->send();
    }

    private function urlMatch($httpMethod, $uri)
    {
        if (false !== $pos = strpos($uri, '?')) {
            $uri = substr($uri, 0, $pos);
        }
        $uri = rawurldecode($uri);
        $route = new Router(self::$config['route']);
        $routeInfo = $route->dispatch($httpMethod, $uri);
        return $this->response->resolve($routeInfo);
    }
    // ...
}
